﻿using ICSharpCode.SharpZipLib.Zip;
using System;
using System.IO;

namespace FCRE.helper
{
    class ZipHelper
    {

        public static void UnpackArchive(string sourceArchiveFileName, string destDir, Func<string, bool> entryFilter, string password)
        {
            ZipFile zipFile = null;
            try
            {
                zipFile = new ZipFile(File.OpenRead(sourceArchiveFileName));
                if (!string.IsNullOrEmpty(password))
                {
                    zipFile.Password = password;
                }
                foreach (ZipEntry item in zipFile)
                {
                    if (item.IsFile)
                    {
                        string name = item.Name;
                        if (entryFilter == null || entryFilter(name))
                        {
                            byte[] buffer = new byte[4096];
                            Stream inputStream = zipFile.GetInputStream(item);
                            string path = Path.Combine(destDir, name);
                            string directoryName = Path.GetDirectoryName(path);
                            if (directoryName.Length > 0)
                            {
                                FileUtils.EnsureDirectoryExists(directoryName, 5);
                            }
                            using (FileStream destination = FileUtils.EnsureFileCreate(path, 5))
                            {
                                StreamUtils.Copy(inputStream, destination, buffer);
                            }
                        }
                    }
                }
            }
            finally
            {
                if (zipFile != null)
                {
                    zipFile.IsStreamOwner = true;
                    zipFile.Close();
                }
            }
        }

        public static void UnpackStreamArchive(Stream sourceStream, string destDir, Func<string, bool> entryFilter, string password)
        {
            ZipInputStream zipInputStream = new ZipInputStream(sourceStream);
            ZipEntry nextEntry = zipInputStream.GetNextEntry();
            while (nextEntry != null)
            {
                string name = nextEntry.Name;
                if (entryFilter != null && !entryFilter(name))
                {
                    nextEntry = zipInputStream.GetNextEntry();
                    continue;
                }
                if (nextEntry.IsDirectory)
                {
                    string text = Path.Combine(destDir, name);
                    if (text.Length > 0)
                    {
                        FileUtils.EnsureDirectoryExists(text, 5);
                    }
                    nextEntry = zipInputStream.GetNextEntry();
                    continue;
                }
                byte[] buffer = new byte[4096];
                string path = Path.Combine(destDir, name);
                string directoryName = Path.GetDirectoryName(path);
                if (directoryName.Length > 0)
                {
                    Directory.CreateDirectory(directoryName);
                }
                using (FileStream destination = FileUtils.EnsureFileCreate(path, 5))
                {
                    StreamUtils.Copy(zipInputStream, destination, buffer);
                }
                nextEntry = zipInputStream.GetNextEntry();
            }
        }

        private static void DoCompress(string path, ZipOutputStream zipStream, int folderOffset, Func<DirectoryInfo, bool> dirFilter, Func<FileInfo, bool> fileFilter)
        {
            bool flag = path.IsDir();
            string[] array = flag ? Directory.GetFiles(path) : new string[1]
            {
        path
            };
            foreach (string text in array)
            {
                FileInfo fileInfo = new FileInfo(text);
                if (fileFilter == null || fileFilter(fileInfo))
                {
                    ZipEntry zipEntry = new ZipEntry(ZipEntry.CleanName(text.Substring(folderOffset)));
                    zipEntry.DateTime = fileInfo.LastWriteTime;
                    zipEntry.Size = fileInfo.Length;
                    zipStream.PutNextEntry(zipEntry);
                    byte[] buffer = new byte[4096];
                    using (FileStream source = File.OpenRead(text))
                    {
                        StreamUtils.Copy(source, zipStream, buffer);
                    }
                    zipStream.CloseEntry();
                }
            }
            if (!flag)
            {
                return;
            }
            array = Directory.GetDirectories(path);
            foreach (string path2 in array)
            {
                if (dirFilter == null || dirFilter(new DirectoryInfo(path2)))
                {
                    DoCompress(path2, zipStream, folderOffset, dirFilter, fileFilter);
                }
            }
        }

        public MemoryStream CompressMemoryArchive(string entryName, MemoryStream sourceMemoryStream, int CompressLevel=3, string UncpackPassword=null)
        {
            MemoryStream memoryStream = new MemoryStream();
            ZipOutputStream zipOutputStream = new ZipOutputStream(memoryStream);
            zipOutputStream.SetLevel(CompressLevel);
            zipOutputStream.Password = UncpackPassword;
            zipOutputStream.PutNextEntry(new ZipEntry(entryName)
            {
                DateTime = DateTime.Now
            });
            StreamUtils.Copy(sourceMemoryStream, zipOutputStream, new byte[4096]);
            zipOutputStream.CloseEntry();
            zipOutputStream.IsStreamOwner = false;
            zipOutputStream.Close();
            memoryStream.Position = 0L;
            return memoryStream;
        }

        public void CompressArchive(string destArchiveFileName, string sourcePath, Func<DirectoryInfo, bool> dirFilter, Func<FileInfo, bool> fileFilter, int CompressLevel = 3, string UncpackPassword = null)
        {
            ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(destArchiveFileName));
            zipOutputStream.SetLevel(CompressLevel);
            zipOutputStream.Password = UncpackPassword;
            int folderOffset = 0;
            if (sourcePath.IsDir())
            {
                folderOffset = sourcePath.Length + ((!sourcePath.EndsWith("\\")) ? 1 : 0);
            }
            DoCompress(sourcePath, zipOutputStream, folderOffset, dirFilter, fileFilter);
            zipOutputStream.IsStreamOwner = true;
            zipOutputStream.Close();
        }


    }

}
